This notebook mirrors sync.mesh.html.
In [1]:
from pathlib import Path
from ipyniivue import download_dataset
BASE_API_URL = "https://niivue.com/demos/images"
DATA_FOLDER = Path("images")
# Download data for example
download_dataset(
BASE_API_URL,
DATA_FOLDER,
files=[
"mni152.nii.gz",
"BrainMesh_ICBM152.lh.mz3",
],
)
mni152.nii.gz already exists. BrainMesh_ICBM152.lh.mz3 already exists. Dataset downloaded successfully to images.
In [2]:
import ipywidgets as widgets
from ipyniivue import DragMode, NiiVue, ShowRender, SliceType
# UI Widgets
dpi_check = widgets.Checkbox(value=False, description="HighDPI")
zoom_check = widgets.Checkbox(value=False, description="2D/3D Zoom Sync")
slice_type = widgets.Dropdown(
options=[
("Axial", SliceType.AXIAL),
("Coronal", SliceType.CORONAL),
("Sagittal", SliceType.SAGITTAL),
("Render", SliceType.RENDER),
("A+C+S+R", SliceType.MULTIPLANAR),
],
value=SliceType.MULTIPLANAR,
description="View",
)
controller = widgets.Dropdown(
options=[
("Independent", 0),
("Top Controls Bottom", 1),
("Bottom Controls Top", 2),
("Bidirectional", 3),
],
value=1,
description="Broadcast",
)
drag_mode = widgets.Dropdown(
options=[
("contrast", DragMode.CONTRAST),
("measurement", DragMode.MEASUREMENT),
("pan/zoom", DragMode.PAN),
("none", DragMode.NONE),
],
value=DragMode.CONTRAST,
description="Drag",
)
mesh_clip_slider = widgets.FloatSlider(
value=11, min=0, max=11.1, step=0.1, description="Mesh Clip"
)
# Info labels
intensity_label_1 = widgets.Label(value=" ")
intensity_label_2 = widgets.Label(value=" ")
# Container for controls
ui_controls = widgets.VBox(
[
widgets.HBox([dpi_check, zoom_check]),
widgets.HBox([slice_type, controller]),
widgets.HBox([drag_mode, mesh_clip_slider]),
]
)
# Initialize NiiVue Instances
nv1 = NiiVue()
nv2 = NiiVue()
# Configure NV1
nv1.opts.back_color = (1, 1, 1, 1)
nv1.opts.multiplanar_show_render = ShowRender.ALWAYS
nv1.opts.is_slice_mm = True
nv1.opts.is_orient_cube = True
nv1.set_clip_plane(0, 180, 40)
# Configure NV2
nv2.opts.back_color = (1, 1, 1, 1)
nv2.opts.multiplanar_show_render = ShowRender.ALWAYS
nv2.opts.is_slice_mm = True
nv2.set_clip_plane(0, 180, 40)
nv2.set_high_resolution_capable(True)
# Load Data
vol_data = [{"path": DATA_FOLDER / "mni152.nii.gz"}]
mesh_data_1 = [
{"path": DATA_FOLDER / "BrainMesh_ICBM152.lh.mz3", "rgba255": [212, 212, 255, 255]}
]
mesh_data_2 = [
{"path": DATA_FOLDER / "BrainMesh_ICBM152.lh.mz3", "rgba255": [222, 255, 222, 255]}
]
nv1.load_volumes(vol_data)
nv1.load_meshes(mesh_data_1)
nv2.load_volumes(vol_data)
nv2.load_meshes(mesh_data_2)
def on_mesh_loaded(mesh):
"""Set mesh shader."""
nv1.set_mesh_shader(mesh.id, "Outline")
nv1.on_mesh_loaded(on_mesh_loaded)
# Sync Logic Init
sync_settings = {"3d": True, "2d": True, "clip_plane": True}
nv1.broadcast_to(nv2, sync_settings) # Default: Top Controls Bottom
# Event Handlers
def on_slice_type_change(change):
"""Handle sliceType change."""
nv1.set_slice_type(change["new"])
nv2.set_slice_type(change["new"])
def on_controller_change(change):
"""Handle controller change."""
val = change["new"]
# 0: Independent
if val == 0:
nv1.broadcast_to([])
nv2.broadcast_to([])
# 1: Top Controls Bottom
elif val == 1:
nv1.broadcast_to(nv2, sync_settings)
nv2.broadcast_to([])
# 2: Bottom Controls Top
elif val == 2:
nv1.broadcast_to([])
nv2.broadcast_to(nv1, sync_settings)
# 3: Bidirectional
elif val == 3:
nv1.broadcast_to(nv2, sync_settings)
nv2.broadcast_to(nv1, sync_settings)
def on_drag_mode_change(change):
"""Handle dragMode change."""
nv1.opts.drag_mode = change["new"]
nv2.opts.drag_mode = change["new"]
def on_dpi_change(change):
"""Handle dpiCheck change."""
nv1.set_high_resolution_capable(change["new"])
def on_zoom_sync_change(change):
"""Handle zoomCheck change."""
is_checked = change["new"]
nv1.opts.yoke_3d_to_2d_zoom = is_checked
nv2.opts.yoke_3d_to_2d_zoom = is_checked
if is_checked:
if len(nv1.scene.pan2d_xyzmm) > 3:
nv1.scene.vol_scale_multiplier = nv1.scene.pan2d_xyzmm[3]
nv1.draw_scene()
if len(nv2.scene.pan2d_xyzmm) > 3:
nv2.scene.vol_scale_multiplier = nv2.scene.pan2d_xyzmm[3]
nv2.draw_scene()
def on_mesh_clip_change(change):
"""Handle mesh clip change."""
val = change["new"]
if val > 10:
val = float("inf")
nv1.opts.mesh_thickness_on_2d = val
def handle_location_change_1(data):
"""Handle nv1 location change."""
intensity_label_1.value = data["string"]
def handle_location_change_2(data):
"""Handle nv2 location change."""
intensity_label_2.value = data["string"]
# Attach observers
slice_type.observe(on_slice_type_change, names="value")
controller.observe(on_controller_change, names="value")
drag_mode.observe(on_drag_mode_change, names="value")
dpi_check.observe(on_dpi_change, names="value")
zoom_check.observe(on_zoom_sync_change, names="value")
mesh_clip_slider.observe(on_mesh_clip_change, names="value")
nv1.on_location_change(handle_location_change_1)
nv2.on_location_change(handle_location_change_2)
# Display
widgets.VBox(
[
ui_controls,
widgets.VBox([nv1, nv2]),
widgets.HBox([intensity_label_1, intensity_label_2]),
]
)
Out[2]: